
#ifndef RTEVENTQUEUEBASE_H
#define RTEVENTQUEUEBASE_H

#include "RtReactorInterface.h"
#include "RtConditionVariable.h"
#include "RtTimeValue.h"
#include <list>

class CRtEventQueueBase;

class RT_FW_EXPORT CRtEventSync : public IRtEvent
{
public:
	CRtEventSync(IRtEvent *aEventPost, CRtEventQueueBase *aEventQueue);
	virtual ~CRtEventSync();

	// interface IRtEvent
	virtual RtResult OnEventFire();
	virtual void OnDestorySelf();

	RtResult WaitResultAndDeleteThis();

private:
	IRtEvent *m_pEventPost;
	RtResult m_Result;
	CRtEventQueueBase *m_pEventQueue;
	BOOL m_bHasDestoryed;
	CRtEventThread m_SendEvent;
};

class RT_FW_EXPORT CRtEventQueueBase : public IRtEventQueue
{
public:
	CRtEventQueueBase();
	virtual ~CRtEventQueueBase();

	// interface IRtEventQueue
	virtual RtResult PostEvent(IRtEvent *aEvent, EPriority aPri = EPRIORITY_NORMAL);
	virtual RtResult SendEvent(IRtEvent *aEvent);
	virtual DWORD GetPendingEventsCount();

	void Stop();
	
	void DestoryPendingEvents();

	void Reset2CurrentThreadId();

	enum { MAX_GET_ONCE = 5 };
	typedef std::list<IRtEvent *> EventsType;

	// Don't make the following two functions static because we want trace size.
	RtResult ProcessEvents(const EventsType &aEvents);
	RtResult ProcessOneEvent(IRtEvent *aEvent);

	static CRtTimeValue s_tvReportInterval;

protected:
	RtResult PopPendingEvents(
		EventsType &aEvents, 
		DWORD aMaxCount = MAX_GET_ONCE, 
		DWORD *aRemainSize = NULL);

	RtResult PopOnePendingEvent(
		IRtEvent *&aEvent, 
		DWORD *aRemainSize = NULL);
	
	EventsType m_Events;
	// we have to record the size of events list due to limition of std::list in Linux.
	DWORD m_dwSize;
	CRtTimeValue m_tvReportSize;

private:
	RT_THREAD_ID m_Tid;
	BOOL m_bIsStopped;

	friend class CRtEventSync;
};

class RT_FW_EXPORT CRtEventQueueUsingMutex : public CRtEventQueueBase 
{
public:
	CRtEventQueueUsingMutex();
	virtual ~CRtEventQueueUsingMutex();

	// interface IRtEventQueue
	virtual RtResult PostEvent(IRtEvent *aEvent, EPriority aPri = EPRIORITY_NORMAL);

	// Pop <aMaxCount> pending events in the queue, 
	// if no events are pending, return at once.
	RtResult PopPendingEventsWithoutWait(
		CRtEventQueueBase::EventsType &aEvents, 
		DWORD aMaxCount = MAX_GET_ONCE, 
		DWORD *aRemainSize = NULL);

	// Pop one pending events, and fill <aRemainSize> with remain size.
	// if no events are pending, return at once.
	RtResult PopOnePendingEventWithoutWait(
		IRtEvent *&aEvent, 
		DWORD *aRemainSize = NULL);

	RtResult PostEventWithOldSize(
		IRtEvent *aEvent, 
		EPriority aPri = EPRIORITY_NORMAL, 
		DWORD *aOldSize = NULL);

private:
	typedef CRtMutexThread MutexType;
	MutexType m_Mutex;
};


// inline functions
inline void CRtEventQueueBase::Reset2CurrentThreadId()
{
	m_Tid = CRtThreadManager::GetThreadSelfId();
}

inline void CRtEventQueueBase::Stop()
{
	m_bIsStopped = TRUE;
}


inline CRtEventQueueUsingMutex::CRtEventQueueUsingMutex()
{
}

inline RtResult CRtEventQueueUsingMutex::
PopPendingEventsWithoutWait(CRtEventQueueBase::EventsType &aEvents, 
							DWORD aMaxCount, DWORD *aRemainSize)
{
	CRtMutexGuardT<MutexType> theGuard(m_Mutex);
	return PopPendingEvents(aEvents, aMaxCount, aRemainSize);
}

inline RtResult CRtEventQueueUsingMutex::
PopOnePendingEventWithoutWait(IRtEvent *&aEvent, DWORD *aRemainSize)
{
	CRtMutexGuardT<MutexType> theGuard(m_Mutex);
	return PopOnePendingEvent(aEvent, aRemainSize);
}

#endif // !RTEVENTQUEUEBASE_H
